﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading;

namespace ClientTest

{
    public class WCFClient
    {
        /// <summary>
        /// 检测掉线的WCF双工客户端事件
        /// </summary>
        /// <param name="DuplexFacotry"></param>
        public delegate void DisConnected_EventHandle(DuplexChannelFactory<Type> DuplexFacotry);

        public static event DisConnected_EventHandle disConnectEvent = null;

        /// <summary>
        /// 保存已建立连接的双工客户端
        /// </summary>
        public static List<DuplexChannelFactory<Type>> list = new List<DuplexChannelFactory<Type>>();

        private static Thread th_Check = null;

        public static void StartCheck()
        {
            if (th_Check == null)
            {
                th_Check = new Thread(CheckDisConnected) { IsBackground = true };
                th_Check.Start();
            }
        }

        /// <summary>
        /// 检测已掉线的WCF双工客户端
        /// </summary>
        static void CheckDisConnected()
        {
            while (true)
            {
                if (list.Count > 0)
                {
                    DuplexChannelFactory<Type> duplexFactory = null;
                    try
                    {
                        for (int i = 0; i < list.Count; i++)
                        {
                            duplexFactory = list[i];
                            if (duplexFactory.State == CommunicationState.Closed || duplexFactory.State == CommunicationState.Faulted)
                            {
                                if (disConnectEvent != null)
                                    disConnectEvent.BeginInvoke(duplexFactory, null, null);
                            }
                        }
                        Thread.Sleep(1000);
                    }
                    catch (Exception ex)
                    {
                        list.Remove(duplexFactory);
                    }
                }
                else
                    Thread.Sleep(1000);
            }
        }

        /// <summary>
        /// 双工客户端连接调用方法
        /// </summary>
        /// <param name="backClient">回调客户端实现方法</param>
        /// <param name="address">URI地址</param>
        /// <returns></returns>
        public static DuplexChannelFactory<T> ConnectDuplexFactory<T>(object backClient, string address)
        {
            DuplexChannelFactory<T> Factory = null;
            try
            {
                InstanceContext instanceContext = new InstanceContext(backClient);
                EndpointAddress endPointAddress = new EndpointAddress(address);
                NetTcpBinding banding = new NetTcpBinding() { MaxBufferSize = int.MaxValue, MaxReceivedMessageSize = int.MaxValue, Security = new NetTcpSecurity() { Mode = SecurityMode.None } };
                banding.ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas();
                banding.ReaderQuotas.MaxArrayLength = int.MaxValue;
                banding.ReaderQuotas.MaxStringContentLength = int.MaxValue;
                banding.ReaderQuotas.MaxDepth = int.MaxValue;
                banding.ReaderQuotas.MaxBytesPerRead = int.MaxValue;
                Factory = new DuplexChannelFactory<T>(instanceContext, banding, endPointAddress);
            }
            catch (Exception ex)
            {
                //Log.Error(ex);
            }
            return Factory;
        }


        /// <summary>
        /// 双工客户端连接调用方法
        /// </summary>
        /// <param name="backClient">回调客户端实现方法</param>
        /// <param name="address">URI地址</param>
        /// <returns></returns>
        public static void ConnectDuplexFactoryByConfig(string clientPoint, out EndpointAddress pointAddress, out NetTcpBinding netBanding)
        {
            try
            {
                string uri = "";
                string contractStr = "";
                string valueStr = ConfigurationManager.AppSettings[clientPoint];
                string[] collectValue = valueStr.Split(',');
                for (int i = 0; i < collectValue.Length; i++)
                {
                    string[] results = collectValue[i].Split('|');
                    if (results.Length == 2)
                    {
                        if (results[0] == "uri")
                            uri = results[1];
                        else if (results[0] == "contract")
                            contractStr = results[1];
                    }
                }
                EndpointAddress endPointAddress = new EndpointAddress(uri);
                NetTcpBinding banding = new NetTcpBinding() { MaxBufferSize = int.MaxValue, MaxReceivedMessageSize = int.MaxValue, Security = new NetTcpSecurity() { Mode = SecurityMode.None } };
                banding.ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas();
                banding.ReaderQuotas.MaxArrayLength = int.MaxValue;
                banding.ReaderQuotas.MaxStringContentLength = int.MaxValue;
                banding.ReaderQuotas.MaxDepth = int.MaxValue;
                banding.ReaderQuotas.MaxBytesPerRead = int.MaxValue;
                pointAddress = endPointAddress;
                netBanding = banding;
            }
            catch (Exception ex)
            {
                //Log.Error(ex);
                pointAddress = null;
                netBanding = null;
            }
        }

        /// <summary>
        /// 通过配置文件的配置键进行单工客户端调用
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="clientConfig"></param>
        /// <returns></returns>
        public static ChannelFactory<T> ConnectChannelFactoryByConfig<T>(string clientConfig)
        {
            return ConnectChannelFactoryByConfig<T>(clientConfig, false);
        }

        /// <summary>
        /// 通过配置文件的配置键进行单工客户端调用
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="clientConfig"></param>
        /// <param name="isNeedAuthentication">是否需要带上验证消息</param>
        /// <returns></returns>
        public static ChannelFactory<T> ConnectChannelFactoryByConfig<T>(string clientConfig, bool isNeedAuthentication)
        {
            string valueStr = ConfigurationManager.AppSettings[clientConfig];
            return ConnectChannelFacotoryByURLStr<T>(valueStr, isNeedAuthentication);
        }

        /// <summary>
        /// 通过文件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="URLStr"></param>
        /// <param name="isNeedAuthentication"></param>
        /// <returns></returns>
        public static ChannelFactory<T> ConnectChannelFacotoryByURLStr<T>(string URLStr, bool isNeedAuthentication = false)
        {
            string uri = "";
            string contractStr = "";
            string[] collectValue = URLStr.Split(',');
            for (int i = 0; i < collectValue.Length; i++)
            {
                string[] results = collectValue[i].Split('|');
                if (results.Length == 2)
                {
                    if (results[0] == "uri")
                        uri = results[1];
                    else if (results[0] == "contract")
                        contractStr = results[1];
                }
            }
            return ConnectChannelFactory<T>(uri, isNeedAuthentication);
        }

        /// <summary>
        /// 单工客户端调用方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="address">URI地址</param>
        /// <returns></returns>
        public static ChannelFactory<T> ConnectChannelFactory<T>(string address)
        {
            return ConnectChannelFactory<T>(address, false);
        }

        /// <summary>
        /// 单工客户端调用方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="address">URI地址</param>
        /// <param name="isNeedAuthentication">是否需要带上验证消息</param>
        /// <returns></returns>
        public static ChannelFactory<T> ConnectChannelFactory<T>(string address, bool isNeedAuthentication)
        {
            ChannelFactory<T> Factory = null;
            try
            {
                EndpointAddress endPointAddress = new EndpointAddress(address);
                NetTcpBinding banding = new NetTcpBinding
                {
                    MaxBufferSize = int.MaxValue,
                    MaxReceivedMessageSize = int.MaxValue,
                    Security = new NetTcpSecurity() { Mode = SecurityMode.None }
                };

                banding.ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas();
                banding.ReaderQuotas.MaxArrayLength = int.MaxValue;
                banding.ReaderQuotas.MaxStringContentLength = int.MaxValue;
                banding.ReaderQuotas.MaxDepth = int.MaxValue;
                banding.ReaderQuotas.MaxBytesPerRead = int.MaxValue;
                Factory = new ChannelFactory<T>(banding, endPointAddress);
            }
            catch (Exception ex)
            {
                //Log.Error(ex.Message);
            }
            return Factory;
        }

        public static void ConnectChannelFactoryByConfig(string clientConfig, out EndpointAddress address, out NetTcpBinding netBanding)
        {
            string uri = "";
            string contractStr = "";
            string valueStr = ConfigurationManager.AppSettings[clientConfig];
            string[] collectValue = valueStr.Split(',');
            for (int i = 0; i < collectValue.Length; i++)
            {
                string[] results = collectValue[i].Split('|');
                if (results.Length == 2)
                {
                    if (results[0] == "uri")
                        uri = results[1];
                    else if (results[0] == "contract")
                        contractStr = results[1];
                }
            }

            EndpointAddress endPointAddress = new EndpointAddress(uri);
            NetTcpBinding banding = new NetTcpBinding
            {
                MaxBufferSize = int.MaxValue,
                MaxReceivedMessageSize = int.MaxValue,
                Security = new NetTcpSecurity() { Mode = SecurityMode.None }
            };

            banding.ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas();
            banding.ReaderQuotas.MaxArrayLength = int.MaxValue;
            banding.ReaderQuotas.MaxStringContentLength = int.MaxValue;
            banding.ReaderQuotas.MaxDepth = int.MaxValue;
            banding.ReaderQuotas.MaxBytesPerRead = int.MaxValue;
            address = endPointAddress;
            netBanding = banding;
        }

        #region 案件中心文件、视频浓缩契约用到

        public static ChannelFactory<T> CreateFactory<T>(string Uri, TransferMode transferMode = TransferMode.Buffered)
        {
            ChannelFactory<T> factory = null;
            EndpointAddress address = new EndpointAddress(Uri);
            NetTcpBinding banding = new NetTcpBinding()
            {
                MaxBufferSize = int.MaxValue,
                MaxReceivedMessageSize = int.MaxValue,
                Security = new NetTcpSecurity() { Mode = SecurityMode.None }
            };
            banding.ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas();
            banding.ReaderQuotas.MaxArrayLength = banding.ReaderQuotas.MaxStringContentLength = banding.ReaderQuotas.MaxDepth = banding.ReaderQuotas.MaxBytesPerRead = int.MaxValue;
            banding.OpenTimeout = banding.CloseTimeout = banding.ReceiveTimeout = banding.SendTimeout = new TimeSpan(1, 0, 0);
            banding.TransferMode = transferMode;
            factory = new ChannelFactory<T>(banding, address);
            factory.Open();
            return factory;
        }

        /// <summary>
        /// 创建回调工厂
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="callbackObject"></param>
        /// <param name="Uri"></param>
        /// <returns></returns>
        public static DuplexChannelFactory<T> CreateDuplexFactory<T>(object callbackObject, string Uri)
        {
            DuplexChannelFactory<T> factory = null;
            EndpointAddress address = new EndpointAddress(Uri);
            NetTcpBinding banding = new NetTcpBinding()
            {
                MaxBufferSize = int.MaxValue,
                MaxReceivedMessageSize = int.MaxValue,
                Security = new NetTcpSecurity() { Mode = SecurityMode.None }
            };

            banding.ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas();
            banding.ReaderQuotas.MaxArrayLength = banding.ReaderQuotas.MaxStringContentLength = banding.ReaderQuotas.MaxDepth = banding.ReaderQuotas.MaxBytesPerRead = int.MaxValue;
            banding.OpenTimeout = banding.CloseTimeout = banding.ReceiveTimeout = banding.SendTimeout = new TimeSpan(1, 0, 0);
            factory = new DuplexChannelFactory<T>(callbackObject, banding, address);
            factory.Open();
            return factory;
        }

        public static void Using<TContract>(TContract proxy, Action action)
        {
            try
            {
                action();
                (proxy as ICommunicationObject).Close();
            }
            catch (CommunicationException ex)
            {
                if (proxy != null)
                    (proxy as ICommunicationObject).Abort();
                throw ex;
            }
            catch (TimeoutException ex)
            {
                if (proxy != null)
                    (proxy as ICommunicationObject).Abort();
                throw ex;
            }
            catch (Exception ex)
            {
                if (proxy != null)
                    (proxy as ICommunicationObject).Close();
                throw ex;
            }
        }

        #endregion
    }
}